import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

createApp(App).mount('#app')

// 因为在 ts 文件默认会识别为全局作用域，加上 export {} 后，才会被识别成一个模块，内部定义的变量就只能在内部作用域访问了
// export {}

// // #region xxx
// function add (num1: number, num2?: number): number {
//   return num1 + num2
// }
// const add2 = (num1: number, num2: number): number => {
//   return num1 + num2
// }
// // #endregion


// // [ xxxx
// type Add = (num1?: number, num2?: number) => number
// const add3: Add = (a, b) => {
//   return a! + b!
// }
// // ] xxx



// // S xxx
// type SayHi = (name: string) => void
// const sayHi: SayHi = (b) => {}
// // E xxx

// console.log('[ add3(1, 2) ]-31', add3(1, 3));



// let person: {
//   name: string;
//   name1: string;
//   name2: string;
//   name3: string;
//   name4: string;
//   name5: string;
//   name6: string;
//   name7: string;
//   sayHi(): void;
// } = {
//   name: 'jack',
//   sayHi() {},
// };


// let person: { name: string; sayHi(): void } = {
//   name: 'jack',
//   sayHi() {},
// };


// let obj = { name: 'zs', age: 18 }

// // 基于已有变量 提取类型
// type Obj = typeof obj

// const obj2: Obj = {
//   name: 'ls',
//   age: 20
// }

// type Student = {
//   name: string;
//   sex: number; // 还没有学枚举类型，思考：性别应该是 固定的几个 可选值
//   score: number;
//   stature?: number;
//   study(): void;
//   playGame?: () => void;
// }


// interface Person {
//   name: string; age: number;
// }

// const obj: Person = {

// }


// type Point1D = {
//   x: number;
// }

// // interface 也可以 extends type
// interface Point2D extends Point1D {
//   y: number;
// }

// // type 也可以 & interface
// type Point3D = Point2D & {
//   z: number;
// }
// // 最终 Point3D 的结构：{ x: number; y: number; z: number }

// const point: Point3D = {
//   x: 1,
//   y: 2,
//   z: 3
// }


// 能省则省原则

// // 函数返回值的类型被自动推断为：number
// // a.js
// export const add = (num1: number, num2: number) => {
//   return num1 + num2;
// };

// // const result = add(1, 2)

// // b.js 文件
// import {add} from 'a.js'

// add



// // let gender = '男'
// // gender = '女'
// // ------------------------
// type Gender = '男' | '女'
// let gender: Gender = '男'
// gender = '女'


// const fn = (n = 18) => {
//   console.log('[ n ] >', n)
// }

// fn('')


// const img = document.getElementById('img') as HTMLImageElement
// // 如果不知道标签的类型：document.querySelector('div') 鼠标摸上去就可以看见
// // img.sr



// // Java 中的 数字类型比较多：Integer、Float、Double、Long 等等...
// // 但是 JS 中 数字类型只有一个：number（暂不考虑ES6新加的）
// // 假设咱们要封装一个 两个变量相加的 函数，目前仅考虑 两个数字相加 和 两个字符串相加

// const addNumber = (a: number, b: number) => a + b
// const addString = (a: string, b: string) => a + b

// const add = <T>(a: T, b: T) => a + b

// // 封装一个本地存储的 Storage
// // 声明一个类（可以指定多个泛型，用逗号分隔）
// class Storage<K, V> {
//   // 声明一个实例属性，属性名如果以 # 开头，表示私有的属性
//   #kvs: Map<K, V> = new Map();

//   // 设置键值对
//   setItem(key: K, value: V) {
//     this.#kvs.set(key, value)
//   }
//   // 根据键 获取对应的 值，如果找不到则返回 undefined
//   getItem(key: K): V | undefined {
//     return this.#kvs.get(key)
//   }
// }

// const storage = new Storage<string, Object>()
// storage.setItem('a', 'A')
// storage.setItem('b', 'B')

// type User = {
//   id: number,
//   name: string,
//   age: number
// }
// const storage2 = new Storage<number, User>()
// const user = storage2.getItem(1)
// console.log('[ user?.age ]-190', user?.age)


// storage.setItem<string>('token', 'xxxx')
// storage.setItem<number>('age', 18)


// storage.getItem('token')


// function identity <T>(value: T) : T {
//   return value;
// }

// // function identity (value: number) : number {
// //   return value;
// // }
// // function identity (value: string) : string {
// //   return value;
// // }
// // function identity (value: Array) : Array {
// //   return value;
// // }

// const res1 = identity<number>(1)

// const res2 = identity<string>('asdfasdf')

// const res3 = identity<[]>([])



// 对象，获取单个ID函数，获取所有ID函数，ID的类型肯定是一致的，但是可能是数字可能是字符串

// // 如果没有泛型，开发者无法穷尽所有的可能情况
// interface IdFn<T, E> {
//   id: () => T;
//   ids: () => E[];
// }

// const idObj: IdFn<number, string> = {
//   id() { 
//     return 123
//   },
//   ids() { 
//     return ['123']
//   },
// };

// const idObj2: IdFn<string, boolean[]> = {
//   id() { 
//     return '123'
//   },
//   ids() { 
//     return [[false], [true], [false, true, true, false]]
//   },
// };

// type User = {
//   id: number,
//   name: string,
//   age: number
// }

// // const users: User[] = []
// const users: Array<User> = []




// const hehe = <T>(id: T): T => {
//   return id
// }


// // 函数的参数是什么类型，返回值就是什么类型
// function getId<T>(id: T): T {
//   return id
// }

// let id1 = getId<number>(1)
// const id2 = getId('2')
// // TS会进行类型推断，参数的类型作为泛型的类型 getId<string>('2')


// interface Point1D {
//   x: number
// }

// interface Point2D {
//   y: number
// }


// interface Point3D extends Point1D, Point2D {
//   z: number
// }

// const point: Point3D = {
//   x: 1,
//   z: 2,
//   y: 3,
// }




// // 1: 男, 2: 女, 3: 未知

// // type Gender = '男' | '女' | '未知'
// type Gender = 1 | 2 | 3 // 这种就丢失语义化了，代码可读性变差，如果有100种值，你是很难记住所有值的含义的。

// const gender: Gender = 2;

// // 假设要调用后台API接口发请求了，但是，接口接收的不是中文，而是 1、2、3

// // 枚举？   说白了，就是列举一些可选项
// //  枚举的选项的默认值从0开始递增
// //  自定义值，只要在可选项名称后面加 = 值 就行了
// enum Gender {
//   男 = 'nan', // 默认值 0
//   女 = 'nv', // 1
//   未知 = 'wz', // 2
// }

// const gender: Gender = Gender.女

// console.log('[ gender ] >', gender)


// enum Direction {
//   up = 1,
//   down = 2,
//   left = 3,
//   right = 4
// }


// 元组：数组的元素由固定的个数和类型组成时，称为元组

// 例如：用一个数组描述一个用户的：姓名、年龄、性别
// let user = ['zs', 18, 'nan']
// user = [1, 2, 3, 4, 5] // 这不会报错，但是，是一个错误的数据

// let user: [string, number?, string?] = ['zs', 18, 'nan']
// user = ['ls', 20, 'zs']
